package com.mibsvc.appsvc.util;

/**
 * Created by Administrator on 2017/5/25.
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;

public class Mjson
        implements Map, Serializable {
    private static final String HEADER_PATH = "ROOT.HEADER";
    private static final String BODY_PATH = "ROOT.BODY";
    private static final String POOL_ID_PATH = "ROOT.HEADER.POOL_ID";
    private static final String ENV_ID_PATH = "ROOT.HEADER.ENV_ID";
    private static final String CONTACT_ID_PATH = "ROOT.HEADER.CONTACT_ID";
    private static final String CHANNEL_ID_PATH = "ROOT.HEADER.CHANNEL_ID";
    private static final String USERNAME_PATH = "ROOT.HEADER.LOGIN.USERNAME";
    private static final long serialVersionUID = -5053942806225519035L;
    private Map<String, Object> ROOT;
    private Map<String, Object> HEADER;
    private Map<String, Object> BODY;
    private Map<String, String> RETURN;
    private boolean isChange = false;
    private boolean isOut = false;
    private String jsonString;

    public Mjson() {
        this.ROOT = new LinkedHashMap();
        this.HEADER = new LinkedHashMap();
        this.set(this.ROOT, "ROOT.HEADER", this.HEADER);

        this.BODY = new LinkedHashMap();
        this.set(this.ROOT, "ROOT.BODY", this.BODY);
        this.RETURN = new LinkedHashMap();
        RETURN.put("RETURN_CODE", "");
        RETURN.put("RETURN_MSG", "");
        this.set(this.ROOT, "ROOT.RETURN", this.RETURN);


        //set(this.ROOT, "ROOT.HEADER.ROUTING.ROUTE_KEY", "");
        //set(this.ROOT, "ROOT.HEADER.ROUTING.ROUTE_VALUE", "");
        set(this.ROOT, "ROOT.HEADER.LOGIN.USERNAME", "");
        //set(this.ROOT, "ROOT.HEADER.LOGIN.PASSWORD", "");
        set(this.ROOT, "ROOT.HEADER.LOGIN.IPADDRESS", "");
        set(this.ROOT, "ROOT.HEADER.LOGIN.MACADDRESS", "");
        //set(this.ROOT, "ROOT.HEADER.OPR.OP_CODE", "");
        //set(this.ROOT, "ROOT.HEADER.OPR.OP_ID", "");
        set(this.ROOT, "ROOT.HEADER.SERVICE.SERVICE_NAME", "");
        set(this.ROOT, "ROOT.HEADER.ACTIVE.ACTIVE_ID", "");

        this.isChange = true;
    }


    public Mjson(String in) {
        this.jsonString = in;
        Map tmpRoot = (Map) JSON.parseObject(in, LinkedHashMap.class);

        this.ROOT = new LinkedHashMap();
        this.HEADER = (Map<String, Object>) (this.getObject(tmpRoot, "ROOT.HEADER"));
        if (null == this.HEADER)
            this.HEADER = new LinkedHashMap();

        set(this.ROOT, "ROOT.HEADER", this.HEADER);

        this.BODY = (Map<String, Object>) (this.getObject(tmpRoot, "ROOT.BODY"));
        if (null == this.BODY)
            this.BODY = new LinkedHashMap();

        this.set(this.ROOT, "ROOT.BODY", this.BODY);

        this.RETURN = (Map<String, String>) (this.getObject(tmpRoot, "ROOT.RETURN"));
        if (null == this.RETURN)
            this.RETURN = new LinkedHashMap();

        this.set(this.ROOT, "ROOT.RETURN", this.RETURN);

    }

    public void setReturnCode(String returnCode) {
        this.RETURN.put("RETURN_CODE", returnCode);

    }

    public void setReturnMsg(String returnMsg) {
        this.RETURN.put("RETURN_MSG", returnMsg);

    }

    public void changed() {
        this.isChange = true;
    }

    public boolean isOut() {
        return this.isOut;
    }

    public void setOut(boolean isOut) {
        this.isChange = true;
        this.isOut = isOut;
    }


    public Map<String, Object> getHeader() {
        Map cloneHead = new LinkedHashMap();
        cloneHead.putAll(this.HEADER);
        return cloneHead;
    }

    public String getServiceName() {
        return ((Map<String, Object>) ((this.getHeader().get("SERVICE")))).get("SERVICE_NAME").toString();
    }

    public String getActiveId() {
        return ((Map<String, Object>) ((this.getHeader().get("ACTIVE")))).get("ACTIVE_ID").toString();
    }

    public Map<String, Object> getBody() {
        return this.BODY;
    }

    public Map<String, String> getReturn() {
        return this.RETURN;
    }


    public String getReturnCode() {
        return this.RETURN.get("RETURN_CODE");
    }

    public String getReturnMsg() {
        return this.RETURN.get("RETURN_MSG");
    }

    public void setRoot(String path, Object value) {
        this.set(this.ROOT, path, value);
    }

    public String getHeaderStr(String path) {
        return ((String) this.getObject(this.HEADER, path));
    }

    public boolean getHeaderBool(String path) {
        return "true".equalsIgnoreCase(this.getObject(this.HEADER, path).toString());
    }

    public Integer getHeaderInt(String path) {
        return ((Integer) this.getObject(this.HEADER, path));
    }

    public Double getHeaderDouble(String path) {
        BigDecimal bd = (BigDecimal) this.getObject(this.HEADER, path);
        return null == bd ? null : Double.valueOf(bd.doubleValue());
    }

    public Long getHeaderLong(String path) {
        Object o = this.getObject(this.HEADER, path);
        if (null == o) {
            return null;
        } else if (o instanceof Long) {
            return ((Long) o);
        } else if (o instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal) o;
            return Long.valueOf(bd.longValue());
        } else {
            Integer i = (Integer) o;
            return Long.valueOf((long) i.intValue());
        }
    }

    public String getBodyStr(String path) {
        Object o = this.getObject(this.BODY, path);
        return null == o ? null : (o instanceof String ? (String) o : o.toString());

    }

    public boolean getBodyBool(String path) {
        return "true".equalsIgnoreCase(this.getObject(this.BODY, path).toString());
    }

    public Integer getBodyInt(String path) {
        return ((Integer) this.getObject(this.BODY, path));
    }

    public Double getBodyDouble(String path) {
        BigDecimal bd = (BigDecimal) this.getObject(this.BODY, path);
        return null == bd ? null : Double.valueOf(bd.doubleValue());
    }

    public Long getBodyLong(String path) {
        Object o = getObject(this.BODY, path);
        if (null == o) return null;
        if (o instanceof Long)
            return ((Long) o);
        if (o instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal) o;
            return Long.valueOf(bd.longValue());
        }
        Integer i = (Integer) o;
        return Long.valueOf((long) i.intValue());
    }

    public Object getBodyObject(String path) {
        return this.getObject(this.BODY, path);
    }

    public <T> T getBodyObject(String path, Class<T> clazz) {
        Object o = this.getObject(this.BODY, path);
        if (null == o) {
            return null;
        } else if (null == clazz) {
            return (T) o;
        } else if (o instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) o;
            return JSON.parseObject(jsonObj.toJSONString(), clazz);
        } else {
            return (T) o;
        }
    }

    public List<?> getBodyList(String path) {
        Object o = this.getObject(this.BODY, path);
        return ((List) o);
    }

    public <T> List<T> getBodyList(String path, Class<T> clazz) {
        Object o = this.getObject(this.BODY, path);
        if (null == o) {
            return null;
        } else if (null == clazz) {
            return (List) o;
        } else if (o instanceof JSONArray) {
            JSONArray jsonArr = (JSONArray) o;
            return JSON.parseArray(JSON.toJSONString(jsonArr), clazz);
        } else if (o instanceof List) {
            return (List) o;
        } else {
            throw new ClassCastException("path=" + path + " " + o.getClass().getName() + " cast " + clazz.getName() + " error");
        }
    }

    private void setBody(String path, Object value) {
        if (null != path && !"".equals(path)) {
            String tmpPath = path;
            if (path.startsWith("ROOT.BODY")) {
                tmpPath = path.substring("ROOT.BODY".length() + 1);
            }

            this.set(this.BODY, tmpPath, value);
        }
    }

    public void addBody(String path, Object value) {
        if (null != path && !"".equals(path)) {
            if (path.startsWith("ROOT.BODY")) {
                path.substring("ROOT.BODY".length() + 1);
            }

            this.add(this.BODY, path, value);
        }
    }


    public String getStr(String path) {
        return (String) this.getObject(this.ROOT, path);
    }

    public boolean getBool(String path) {
        return "true".equalsIgnoreCase(this.getObject(this.ROOT, path).toString());
    }

    public Integer getInt(String path) {
        return ((Integer) this.getObject(this.ROOT, path));
    }

    public Double getDouble(String path) {
        BigDecimal bd = (BigDecimal) this.getObject(this.ROOT, path);
        return null == bd ? null : Double.valueOf(bd.doubleValue());
    }

    public Long getLong(String path) {
        Object o = this.getObject(this.ROOT, path);
        if (null == o) {
            return null;
        } else if (o instanceof Long) {
            return (Long) o;
        } else if (o instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal) o;
            return Long.valueOf(bd.longValue());
        } else {
            Integer i = (Integer) o;
            return Long.valueOf((long) i.intValue());
        }
    }

    public Object getObject(String path) {
        return this.getObject(this.ROOT, path);
    }

    public <T> T getObject(String path, Class<T> clazz) {
        Object o = this.getObject(this.ROOT, path);
        if (null == o) {
            return null;
        } else if (null == clazz) {
            return (T) o;
        } else if (o instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) o;
            return JSON.parseObject(jsonObj.toJSONString(), clazz);
        } else {
            return (T) o;
        }
    }

    public List<?> getList(String path) {
        Object o = this.getObject(this.ROOT, path);
        return ((List) o);
    }

    public <T> List<T> getList(String path, Class<T> clazz) {
        Object o = this.getObject(this.ROOT, path);
        if (null == o) {
            return null;
        } else if (null == clazz) {
            return (List) o;
        } else if (o instanceof JSONArray) {
            JSONArray jsonArr = (JSONArray) o;
            return JSON.parseArray(JSON.toJSONString(jsonArr), clazz);
        } else if (o instanceof List) {
            return (List) o;
        } else {
            throw new ClassCastException("path=" + path + " " + o.getClass().getName() + " cast " + clazz.getName() + " error");
        }
    }

    public void renameBody(String oldPath, String newPath) {
        if (null != oldPath && !"".equals(oldPath)) {
            if (null != newPath && !"".equals(newPath)) {
                String tmpOldPath = oldPath;
                if (oldPath.startsWith("ROOT.BODY")) {
                    tmpOldPath = oldPath.substring("ROOT.BODY".length() + 1);
                }

                String tmpNewPath = newPath;
                if (newPath.startsWith("ROOT.BODY")) {
                    tmpNewPath = newPath.substring("ROOT.BODY".length() + 1);
                }

                this.rename(this.BODY, tmpOldPath, tmpNewPath);
            }
        }
    }

    private void rename(Map map, String oldPath, String newPath) {
        Object o = this.getObject(map, oldPath);
        this.remove(map, oldPath);
        this.set(map, newPath, o);
    }

    private void remove(Map map, String path) {
        if (null != path && !"".equals(path)) {
            this.isChange = true;
            Map subMap = map;
            String[] keys = path.split("\\.");
            if (keys.length < 2) {
                Object o = map.get(path);
                if (null != o) {
                    map.remove(path);
                }
            } else {
                int i;
                for (i = 0; i < keys.length - 1; ++i) {
                    if (null == subMap) {
                        return;
                    }

                    subMap = (Map) subMap.get(keys[i]);
                }

                if (null != subMap) {
                    subMap.remove(keys[i]);
                }
            }
        }
    }

    private Object getObject(Map map, String path) {
        if (null != path && !"".equals(path) && null != map) {
            Map subMap = map;
            String[] keys = path.split("\\.");
            if (keys.length < 2) {
                return map.get(path);
            } else {
                int i;
                for (i = 0; i < keys.length - 1; ++i) {
                    if (null == subMap) {
                        return null;
                    }

                    subMap = (Map) subMap.get(keys[i]);
                }

                if (null == subMap) {
                    return null;
                } else {
                    return subMap.get(keys[i]);
                }
            }
        } else {
            return null;
        }
    }

    private void setHead(String path, Object value) {
        this.set(this.HEADER, path, value);
    }


    public void setHeader(Map<String, Object> header) {
        this.HEADER = header;
        this.set(this.ROOT, "ROOT.HEADER", header);
    }

    public Mjson setBody(Map<String, Object> body) {
        this.BODY = body;
        this.set(this.ROOT, "ROOT.BODY", body);
        return this;
    }

    public void setReturn(Map<String, String> returnMap) {
        this.RETURN = returnMap;
        this.set(this.ROOT, "ROOT.RETURN", returnMap);
    }

    private void add(Map map, String path, Object value) {
        this.isChange = true;
        Object o = this.getObject(map, path);
        if (null == o) {
            this.setBody(path, value);
        } else if (o instanceof Collection) {
            ((Collection) o).add(value);
        } else {
            List<Object> l = new ArrayList(4);
            l.add(o);
            l.add(value);
            this.setBody(path, l);
        }
    }

    private void set(Map map, String path, Object value) {
        if (null != path && !"".equals(path)) {
            this.isChange = true;
            Map subMap = map;
            String[] keys = path.split("\\.");
            if (keys.length < 2) {
                map.put(path, value);
            } else {
                int i = 0;
                Map tmp = null;
                Object o = null;
                int index = 1;
                int arrIndex = 1;
                String tmpKey = null;

                for (String tmpIndex = null; i < keys.length - 1; ++i) {
                    tmpKey = keys[i];
                    index = tmpKey.indexOf(91);
                    if (index > 0) {
                        tmpIndex = tmpKey.substring(index + 1);
                        tmpIndex = tmpIndex.substring(0, tmpIndex.length() - 1);
                        tmpKey = tmpKey.substring(0, index);
                        arrIndex = Integer.parseInt(tmpIndex);
                        o = ((Map) subMap).get(tmpKey);
                        if (null == o) {
                            tmp = null;
                        } else if (o instanceof List) {
                            tmp = (Map) ((List) o).get(arrIndex);
                        } else {
                            tmp = null;
                        }
                    } else {
                        tmp = (Map) ((Map) subMap).get(keys[i]);
                    }

                    if (null == tmp) {
                        tmp = new LinkedHashMap();
                        ((Map) subMap).put(keys[i], tmp);
                    }

                    subMap = tmp;
                }

                ((Map) subMap).put(keys[i], value);
            }
        }
    }

    public String toString() {
        if (!this.isChange) {
            return this.jsonString;
        } else {
            SerializerFeature[] features = new SerializerFeature[]{SerializerFeature.DisableCircularReferenceDetect};
            String dateFormat = "yyyyMMdd HHmmss";
            if (this.isOut) {
                Map<String, Object> outRoot = new LinkedHashMap(1);
                this.set(outRoot, "ROOT.BODY", this.BODY);
                this.jsonString = JSON.toJSONStringWithDateFormat(outRoot, dateFormat, features);
            } else {
                this.jsonString = JSON.toJSONStringWithDateFormat(this.ROOT, dateFormat, features);
            }

            this.isChange = false;
            return this.jsonString;
        }
    }

    public int size() {
        return this.ROOT.size();
    }

    public boolean isEmpty() {
        return this.ROOT.isEmpty();
    }

    public boolean containsKey(Object key) {
        return this.ROOT.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return this.ROOT.containsValue(value);
    }

    public Object get(Object key) {
        return this.ROOT.get(key);
    }

    public Object put(Object key, Object value) {
        return null;
    }

    public Object remove(Object key) {
        return null;
    }

    public void putAll(Map m) {
    }

    public void clear() {
    }

    public Set keySet() {
        return null;
    }

    public Collection values() {
        return null;
    }

    public Set entrySet() {
        return null;
    }

    public String toReturnString() {
        System.out.println(("出参" + this.toString()));
        Mjson m = new Mjson(this.toString());

        if(m.getReturnCode().equals("")){
            m.setReturnCode("666");
            m.setReturnMsg("服务调用成功");
        }
        return m.toString();
    }
}